/// ParentDataWidget 示例 
/// copy 到 main.dart 中就能执行

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';

class Test extends StatelessWidget {
  const Test({super.key});

  @override
  Widget build(BuildContext context) {
    return Container();
  }
}

void main() async {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> with TickerProviderStateMixin {
 
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Scaffold(
            body: MyStack(
      children: [
        MyPositioned(
            left: 10,
            child: Container(
              width: 100,
              height: 100,
              color: Colors.green,
              child:const Text('I AM 17'),
            ))
      ],
    )));
  }
}

class MyStackParentData extends ContainerBoxParentData<RenderBox> {
  MyStackParentData({this.left});
  double? left;
}

class MyStack extends MultiChildRenderObjectWidget {
  MyStack({Key? key, required List<MyPositioned> children})
      : super(key: key, children: children);

  @override
  RenderObject createRenderObject(BuildContext context) {
    return MyRenderStack();
  }
}

class MyRenderStack extends RenderBox
    with
        ContainerRenderObjectMixin<RenderBox, MyStackParentData>,
        RenderBoxContainerDefaultsMixin<RenderBox, MyStackParentData> {
  @override
  void setupParentData(RenderBox child) {
    if (child.parentData is! MyStackParentData) {
      child.parentData = MyStackParentData();
    }
  }

  @override
  bool get sizedByParent => true;

  @override
  Size computeDryLayout(BoxConstraints constraints) {
    return constraints.biggest;
  }

  @override
  void paint(PaintingContext context, Offset offset) {
    paintStack(context, offset);
  }

  @protected
  void paintStack(PaintingContext context, Offset offset) {
    defaultPaint(context, offset);
  }

  @override
  void performLayout() {
    RenderBox? child = firstChild;
    while (child != null) {
      final MyStackParentData childParentData =
          child.parentData! as MyStackParentData;
      double x = 0, y = 0;
      if (childParentData.left != null) {
        x = childParentData.left!;
      }
      childParentData.offset = Offset(x, y);
      //因为只是演示，简化代码，直接固定宽高 100
      child.layout(constraints.tighten(width: 100, height: 100),
          parentUsesSize: false);
      child = childParentData.nextSibling;
    }
  }
}

class MyPositioned extends ParentDataWidget<MyStackParentData> {
  const MyPositioned({required this.left, Key? key, required Widget child})
      : super(key: key, child: child);
  final double? left;
  @override
  void applyParentData(RenderObject renderObject) {
    assert(renderObject.parentData is MyStackParentData);
    final MyStackParentData parentData =
        renderObject.parentData! as MyStackParentData;
    bool needsLayout = false;

    if (parentData.left != left) {
      parentData.left = left;
      needsLayout = true;
    }
    if (needsLayout) {
      final AbstractNode? targetParent = renderObject.parent;
      if (targetParent is RenderObject) {
        targetParent.markNeedsLayout();
      }
    }
  }

  @override
  Type get debugTypicalAncestorWidgetClass => MyStack;
}

